package com.gitee.qdbp.general.common.biz.settings.service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.gitee.qdbp.able.beans.KeyString;
import com.gitee.qdbp.able.exception.ServiceException;
import com.gitee.qdbp.able.jdbc.ordering.OrderPaging;
import com.gitee.qdbp.able.jdbc.paging.PageList;
import com.gitee.qdbp.able.jdbc.paging.Paging;
import com.gitee.qdbp.able.result.ResultCode;
import com.gitee.qdbp.general.common.api.settings.basic.IAreaDivisionBasic;
import com.gitee.qdbp.general.common.api.settings.model.AreaBean;
import com.gitee.qdbp.general.common.api.settings.model.AreaDivisionBean;
import com.gitee.qdbp.general.common.api.settings.model.AreaDivisionWhere;
import com.gitee.qdbp.general.common.api.settings.service.IAreaDivisionQueryer;
import com.gitee.qdbp.general.common.enums.AreaType;
import com.gitee.qdbp.tools.cache.ICacheService;
import com.gitee.qdbp.tools.codec.CodeTools;
import com.gitee.qdbp.tools.utils.ConvertTools;
import com.gitee.qdbp.tools.utils.StringTools;
import com.gitee.qdbp.tools.utils.VerifyTools;

/**
 * 行政区划业务处理类
 *
 * @author zhh
 * @version 170702
 */
@Service
@Transactional(readOnly = true)
public class AreaDivisionQueryer implements IAreaDivisionQueryer {

    /** 日志对象 **/
    private static final Logger log = LoggerFactory.getLogger(AreaDivisionQueryer.class);

    @Autowired
    private IAreaDivisionBasic areaDivisionBasic;
    @Autowired
    private ICacheService cacheService;
    /** key=AreaDivision:{scene}, value={areaCode:AreaBean} **/
    protected static String AREA_DIVISION_KEY = "AreaDivision";

    @Override
    public AreaBean findByCode(String scene, String areaCode) throws ServiceException {
        if (VerifyTools.isBlank(scene)) {
            log.error("params is null: SceneType");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(areaCode)) {
            log.error("params is null: areaCode");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        AreaBean bean = cacheService.hget(AREA_DIVISION_KEY, scene, areaCode, AreaBean.class);
        if (bean == null) {
            AreaDivisionWhere w = new AreaDivisionWhere();
            w.setSceneType(scene);
            w.setAreaCode(areaCode);
            AreaDivisionBean temp = areaDivisionBasic.find(w);
            if (temp == null) {
                bean = null;
            } else {
                bean = temp.to(AreaBean.class);
                cacheService.hset(AREA_DIVISION_KEY, scene, areaCode, bean);
            }
        }
        return bean;
    }

    private PageList<AreaDivisionBean> listAllFromDb(String scene) throws ServiceException {
        AreaDivisionWhere w = new AreaDivisionWhere();
        w.setSceneType(scene);
        OrderPaging paging = OrderPaging.of(Paging.NONE, "type ASC, sortIndex ASC");
        return areaDivisionBasic.list(w, paging);
    }

    @Override
    public List<AreaBean> listAll(String scene) throws ServiceException {
        if (VerifyTools.isBlank(scene)) {
            log.error("params is null: SceneType");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        if (cacheService.exist(AREA_DIVISION_KEY, scene)) {
            // 从缓存中查询
            Map<String, AreaBean> map = cacheService.haget(AREA_DIVISION_KEY, scene, AreaBean.class);
            if (map.isEmpty()) {
                return null;
            } else {
                Collection<AreaBean> values = map.values();
                List<AreaBean> list = new ArrayList<>();
                list.addAll(values);
                Collections.sort(list);
                return list;
            }
        } else {
            // 从数据库查询
            PageList<AreaDivisionBean> temp = listAllFromDb(scene);
            if (temp == null) {
                return null;
            } else {
                List<AreaDivisionBean> beans = temp.toList();
                List<AreaBean> list = new ArrayList<>();
                for (AreaDivisionBean bean : beans) {
                    list.add(bean.to(AreaBean.class));
                }
                // 放入缓存
                Map<String, AreaBean> map = new HashMap<>();
                for (AreaBean bean : list) {
                    map.put(bean.getAreaCode(), bean);
                }
                cacheService.hmset(AREA_DIVISION_KEY, scene, map);
                return list;
            }
        }
    }

    @Override
    public String findAreaText(String scene, String areaCode) throws ServiceException {
        if (VerifyTools.isBlank(scene)) {
            log.error("params is null: SceneType");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(areaCode)) {
            return null;
        }

        List<String> areaCodes = new ArrayList<>();
        {
            List<String> temp = CodeTools.split(areaCode, 2, true);
            for (String item : temp) {
                areaCodes.add(StringTools.pad(item, '0', false, 6));
            }
        }
        // 先尝试按标准编号查询上级
        Map<String, AreaBean> areas = cacheService.hmget(AREA_DIVISION_KEY, scene, areaCodes, AreaBean.class);

        ArrayList<String> buffer = new ArrayList<>();
        String tempCode = areaCode;
        String lastName = null;
        AreaType lastType = null;
        while (tempCode != null) {
            AreaBean bean = areas.get(tempCode);
            if (bean == null && lastType != AreaType.PROVINCE) {
                // 没找到就单独查询, 因为有些行政区划不是完全标准的, 上级编号不一定是下级编号前几位补0
                bean = findByCode(scene, tempCode);
            }
            if (bean == null || bean.getType() == AreaType.COUNTRY) {
                break;
            }
            String shortName = AreaDivisionTools.getShortName(bean);
            if (lastName == null || !lastName.equals(shortName)) {
                buffer.add(0, shortName);
            }
            tempCode = bean.getParentCode();
            lastName = shortName;
            lastType = bean.getType();
        }
        return buffer.isEmpty() ? null : ConvertTools.joinToString(buffer, " ");
    }

    @Override
    public List<KeyString> listAreaText(String scene, List<String> areaCodes) throws ServiceException {
        if (VerifyTools.isBlank(scene)) {
            log.error("params is null: SceneType");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }
        if (VerifyTools.isBlank(areaCodes)) {
            return null;
        }

        Map<String, AreaBean> map;
        if (cacheService.exist(AREA_DIVISION_KEY, scene)) {
            // 从缓存中查询
            map = cacheService.haget(AREA_DIVISION_KEY, scene, AreaBean.class);
        } else {
            // 从数据库查询
            PageList<AreaDivisionBean> temp = listAllFromDb(scene);
            if (temp == null) {
                return null;
            } else {
                List<AreaDivisionBean> list = temp.toList();
                map = new HashMap<>();
                for (AreaBean bean : list) {
                    map.put(bean.getAreaCode(), bean.to(AreaBean.class));
                }
                // 放入缓存
                cacheService.hmset(AREA_DIVISION_KEY, scene, map);
            }
        }

        return AreaDivisionTools.getAreaText(areaCodes, map);
    }

    @Override
    public AreaDivisionBean find(AreaDivisionWhere where) throws ServiceException {
        if (VerifyTools.isBlank(where.getSceneType())) {
            log.error("params is null: SceneType");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        return areaDivisionBasic.find(where);
    }

    @Override
    public PageList<AreaDivisionBean> list(AreaDivisionWhere where, OrderPaging paging) throws ServiceException {
        if (VerifyTools.isBlank(where.getSceneType())) {
            log.error("params is null: SceneType");
            throw new ServiceException(ResultCode.PARAMETER_IS_REQUIRED);
        }

        return areaDivisionBasic.list(where, paging);
    }

}
